/* 
Makes columns sortable by clicking on the appropriate column header. 
*/

function RowSortModule() {

	var base = this;
	var liteGrid;
	var options;

	//Hooks in to liteGrid.
	base.initialize = function(grid, opts) {

		//The headers need to be modified after the layout provider has created them.
		liteGrid = grid;
		options = opts;

		liteGrid.$el.bind("headerRendered", base.makeHeadersClickable);

		//An arrow that is used to indicate sort direction.
		base.sortArrow = $("<div class='sort-arrow ui-icon'/>");
		//Will be used to store the column that was last sorted on.
		base.sortColumn = null;
		//True if the last sort was ascending, false otherwise.
		base.sortAsc = false;
	}

	//Converts the table headers into clickable headers that will sort the grid.
	base.makeHeadersClickable = function() {

		//Loop through the headers and mark those that are sortable as sortable.
		$(options.columns).each(function(i) {
			if (this.sortable === true) {
				$("th:eq(" + i + ")", liteGrid.headerTable).addClass("sortable");
			}
		});

		//Bind a click handler to the sortable ones.
		$("th.sortable", liteGrid.headerTable).click(base.columnClicked);
	}
	
	//Performs the actual sort.
	base.columnClicked = function() {
		var header = $(this);

		//Get the zero-based index and column that was clicked.
		var index = header.parent().children().index(header);
		var column = options.columns[index];

		//If this is the same column we already sorted, toggle the direction
		if (base.sortColumn == column) {
			base.sortAsc = !base.sortAsc;
		}
		//Otherwise, reset it to sort ascending
		else {
			base.sortColumn = column;
			base.sortAsc = true;
		}

		if (base.sortAsc) {
			base.sortArrow.removeClass("ui-icon-carat-1-s");
			base.sortArrow.addClass("ui-icon-carat-1-n");
		}
		else {
			base.sortArrow.removeClass("ui-icon-carat-1-n");
			base.sortArrow.addClass("ui-icon-carat-1-s");
		}

		//Extract key/list pairs where the key is the value for the row being sorted, and the list is
		//the row and its children.
		var sortItems = [];
		//Used for quickly finding a row by its ID.
		var lookup = {};

		//Each row is added either to the root sortItems array or to the children array of its parent.
		$("tr", liteGrid.$el).each(function() {
			var row = $(this);
			var dataItem = row.data("dataItem");
			//This represents the row that will be sorted.
			var sortItem = { key: dataItem[base.sortColumn.field], row: row, children: [] };

			lookup[dataItem[options.rowIdColumn]] = sortItem;

			//If the row doesn't have a parent, it goes in the root list, otherwise it gets added to
			//its parent sortItem
			if (row.attr("parentId")) {
				lookup[row.attr("parentId")].children.push(sortItem);
			}
			else {
				sortItems.push(sortItem);
			}
		});

		//Recursively sort the rows in memory and re-append them to the table.
		base.doSortAndAppend(sortItems);

		//Add the sort indicator to the header.
		base.sortArrow.appendTo($("> div", header));

		//The row order has changed
		liteGrid.$el.trigger("tableUpdated", liteGrid);
	}

	//Recursively sorts the rows and append them to the table.
	base.doSortAndAppend = function(sortItems) {
		sortItems.sort(base.compare);

		$(sortItems).each(function() {

			var sortItem = this;

			//Add the row to the grid.
			sortItem.row.appendTo($("tbody", liteGrid.$el));
			
			if (sortItem.children.length > 0) {
				base.doSortAndAppend(sortItem.children);
			}
		});
	}

	//Compares left to right, returning -1 if left is smaller, 0 if they are equal,
	//and 1 if left is larger (logic is inverted if sortAsc is false).
	base.compare = function(left, right) {

		var leftValue = left.key;
		var rightValue = right.key;

		var result;

		if (leftValue == rightValue) 
			return 0;

		if (leftValue > rightValue)
			result = 1;
		else
			result = -1;

		if (base.sortAsc) {
			return result;
		}
		else {
			return -1 * result;
		}
	}
}